import json
import sys
import os
import logging
from pathlib import Path
from typing import Dict, List, Optional

# sys.path.append(r'T:\CGRepository\CGCodeRepos\pyLibs\python3\pyqt')

from PyQt5.QtWidgets import (QApplication, QSystemTrayIcon, QMenu, QAction,
                             QMessageBox, QStyle)
from PyQt5.QtGui import QIcon
from PyQt5.QtCore import QProcess

import subprocess
from functools import partial
from utlis import *

# 配置日志
logging.basicConfig(
    level=logging.INFO,
    format='%(asctime)s - %(name)s - %(levelname)s - %(message)s',
    handlers=[
        logging.FileHandler(os.path.join(os.environ.get('JTK_TRAY_PATH', ''), 'tray.log')),
        logging.StreamHandler()
    ]
)
logger = logging.getLogger(__name__)


class JTKTrayApp:
    def __init__(self, config_file: str):
        # 初始化Qt应用
        self.app = QApplication.instance() or QApplication(sys.argv)
        self.config_file = config_file

        # config env
        # self.python_exec = os.environ['PYTHON'].split(';')[0]
        # self.jtk_cg = os.environ['JTK_CG']
        self.jtk_launcher_path = os.environ['JTK_LAUNCHER_PATH']
        self.jtk_tray_path = os.environ['JTK_TRAY_PATH']

        # 创建主菜单
        self.main_menu = QMenu()
        self.refresh()

        # Windows下设置AppUserModelID（重要！）
        if sys.platform == "win32":
            self.setup_windows()
            # import ctypes
            # ctypes.windll.shell32.SetCurrentProcessExplicitAppUserModelID('myapp.pyside2.1.0')

        # 创建系统托盘图标
        self.tray_icon = QSystemTrayIcon()
        self.setup_icon()

        # 完成设置
        self.tray_icon.setContextMenu(self.main_menu)
        self.tray_icon.setToolTip(self.config.get("tooltip", "JTK.v2.0"))
        self.tray_icon.show()

    def setup_windows(self):
        """Windows平台特定设置"""
        import ctypes
        # 设置AppUserModelID确保通知正常显示
        ctypes.windll.shell32.SetCurrentProcessExplicitAppUserModelID('JTK2.0')
        # 隐藏控制台窗口
        if sys.argv[0].endswith('.py'):
            ctypes.windll.user32.ShowWindow(ctypes.windll.kernel32.GetConsoleWindow(), 0)

    def setup_icon(self):
        """设置托盘图标"""
        icon_path = os.path.join(self.jtk_tray_path, self.config['icon'])
        if os.path.exists(icon_path):
            self.tray_icon.setIcon(QIcon(icon_path))
        else:
            # 使用系统内置图标作为后备
            self.tray_icon.setIcon(self.app.style().standardIcon(QStyle.SP_ComputerIcon))

    def load_config(self, config_file):
        """加载JSON配置文件"""
        try:
            with open(config_file, 'r', encoding='utf-8') as f:
                return json.load(f)
        except Exception as e:
            print(f"{config_file}: 加载配置文件失败: {e}")
            # # 返回一个默认配置
            # return {
            #     "menu_title": "无菜单",
            #     "menu_items": [
            #         {
            #             "title": "退出",
            #             "action": "quit"
            #         }
            #     ]
            # }

    # def build_launcher_menu(self, config):

    def build_menu_from_config(self, items, parent_menu):
        """递归构建菜单结构"""
        for item in items:
            if "submenu" in item:
                # 创建子菜单
                submenu = parent_menu.addMenu(item["title"])
                submenu.setStyleSheet("QMenu {font-size:11pt;}")

                icon_path = '{}/config/{}'.format(self.jtk_launcher_path, item["icon"])
                if os.path.isfile(icon_path):
                    icon = QIcon(icon_path)
                    submenu.setIcon(icon)
                self.build_menu_from_config(item["submenu"], submenu)
            else:
                # 创建菜单项
                action = QAction(item["title"], parent_menu)

                icon_path = '{}/config/{}'.format(self.jtk_launcher_path, item["icon"])
                if os.path.isfile(icon_path):
                    action.setIcon(QIcon(icon_path))
                # 根据action类型设置触发事件
                action_type = item.get("action", "")
                if action_type == "launch":
                    action.triggered.connect(
                        partial(self.launch_application, item["command"], item['desc'])
                    )
                elif action_type == "refresh":
                    action.triggered.connect(
                        self.refresh
                    )
                elif action_type == "computer_info":
                    action.triggered.connect(
                        self.show_computer_info
                    )
                elif action_type == "run_script":
                    action.triggered.connect(
                        self.show_message
                    )
                elif action_type == "quit":
                    action.triggered.connect(self.quit_application)

                parent_menu.addAction(action)

    def launch_application(self, command, desc):
        """启动应用程序"""
        try:
            lc_path = os.environ['JTK_LAUNCHER_PATH']
            # case 1. by .py file
            # cmd_argv = [self.python_exec]
            # cmd_argv = [r'T:\CGRepository\Python\Python310\python.exe']
            # cmd_argv.append(lc_path + '/JTKLauncher.py')
            # cmd_argv.append('310')
            # case 2. by .exe file
            cmd_argv = [lc_path + '/JTKLauncher.exe']
            # cmd_argv = [r'D:\SyncWorkspace\CGRepository\CGCodeRepos\dist\JTKLauncher\JTKLauncher.exe']
            cmd_argv.append(command)
            os.environ['PYTHONPATH'] = ''
            print(cmd_argv)
            subprocess.Popen(cmd_argv, subprocess.PIPE, stderr=subprocess.PIPE, stdin=subprocess.PIPE, shell=True)
            # if wait:
            #     proc.wait()

            self.show_notification(f"{command}-启动中", f"{desc}")
        except Exception as e:
            self.show_notification("启动失败", f"无法启动程序: {str(e)}", is_error=True)

    def show_notification(self, title, message, is_error=False):
        """显示系统通知"""
        icon_type = QSystemTrayIcon.Critical if is_error else QSystemTrayIcon.Information
        self.tray_icon.showMessage(title, message, icon_type, 3000)

    def refresh(self):
        # 加载配置文件
        self.config = self.load_config(self.config_file)
        self.app.setApplicationName(self.config['title'])
        # 创建右键菜单
        self.main_menu.clear()
        # build launcher
        lc_config = os.path.join(self.jtk_launcher_path, 'config')
        lc_menu_file = os.path.join(lc_config, 'menu.json')
        if os.path.exists(lc_menu_file):
            lc_data = self.load_config(lc_menu_file)
            lc_menu_name = lc_data.get('title', 'launcher')
            lc_menu_icon = lc_data.get('icon', '')
            lc_menu_list = lc_data.get('menu', [])

            # 创建子菜单
            lc_menu = self.main_menu.addMenu(lc_menu_name)
            lc_menu.setStyleSheet("QMenu {font-size:11pt;}")

            icon_path = '{}/config/{}'.format(self.jtk_launcher_path, lc_menu_icon)
            if os.path.isfile(icon_path):
                icon = QIcon(icon_path)
                lc_menu.setIcon(icon)

            for menu_data in lc_menu_list:
                menu_name = menu_data.get('title', 'JTK_LC')
                menu_icon = menu_data.get('icon', "icons/none.ico")
                menu_action_list = menu_data.get('action', [])
                if menu_icon == "":
                    menu_icon = "icons/none.ico"
                submenu = lc_menu.addMenu(menu_name)
                icon_path = '{}/config/{}'.format(self.jtk_launcher_path, menu_icon)
                if os.path.isfile(icon_path):
                    icon = QIcon(icon_path)
                    submenu.setIcon(icon)
                for ac in menu_action_list:
                    action = QAction(ac, submenu)
                    lc_config_file = os.path.join(lc_config, 'launcher', ac + '.json')
                    # print(lc_config_file)
                    if os.path.exists(lc_config_file):
                        lc_data = self.load_config(lc_config_file)
                        action_name = lc_data.get('name', 'noAssignName')
                        action_icon = lc_data.get('icon', "icons/none.ico")
                        if action_icon == "":
                            action_icon = "icons/none.ico"
                        action_desc = lc_data.get('desc', 'none')

                        icon_path = '{}/config/{}'.format(self.jtk_launcher_path, action_icon)
                        if os.path.isfile(icon_path):
                            action.setIcon(QIcon(icon_path))
                        action.triggered.connect(
                            partial(self.launch_application, ac, action_desc))
                    submenu.addAction(action)

        # build tools
        self.build_menu_from_config(self.config["menu_items"], self.main_menu)

        # add app action
        # refresh
        refresh_action = QAction("刷新", self.main_menu)
        refresh_action.triggered.connect(self.refresh)
        self.main_menu.addAction(refresh_action)
        # quit
        quit_action = QAction("退出", self.main_menu)
        quit_action.triggered.connect(self.quit_application)
        self.main_menu.addAction(quit_action)

    def show_computer_info(self):
        host = get_host_name()
        user = get_user_name()
        ip = get_local_ip()
        mac = get_mac_address()
        hardware = get_Hardware_info()
        self.tray_icon.showMessage(
            f"{user}",
            f"HARD: {hardware}\nHOST: {host}\nIP: {ip}\nMAC: {mac}",
            QSystemTrayIcon.Information,
            5000
        )

    def show_message(self):
        self.tray_icon.showMessage(
            "showMessage",
            "这是来自托盘程序的消息",
            QSystemTrayIcon.Information,
            5000
        )

    def quit_app(self):
        self.tray_icon.hide()
        self.app.quit()

    def on_tray_icon_activated(self, reason):
        if reason == QSystemTrayIcon.DoubleClick:
            self.show_message()

    def quit_application(self):
        """退出应用程序"""
        self.tray_icon.hide()
        self.app.quit()

    def run(self):
        """运行应用程序"""
        sys.exit(self.app.exec_())


if __name__ == "__main__":
    # 在Windows下隐藏控制台窗口（如果是.pyw文件会自动隐藏）
    if sys.platform == "win32" and sys.argv[0].endswith('.py'):
        import ctypes

        ctypes.windll.user32.ShowWindow(ctypes.windll.kernel32.GetConsoleWindow(), 0)

    # jtk tray path to env
    current_path = os.getcwd()
    os.environ['JTK_TRAY_PATH'] = current_path
    config_path = os.path.join(current_path, 'config')
    config_file = os.path.join(config_path, 'config.ini')
    setup_env(config_file)
    # jtk tray menu
    tray_menu_file = os.path.join(config_path, 'tools_menu.json')
    app = JTKTrayApp(tray_menu_file)
    args = sys.argv
    if len(args) == 1:
        app.run()
    # else:
    #     jtk_launcher_path = os.environ['JTK_LAUNCHER_PATH']
    # sys.argv[1]
    # app.run()
    # sys.exit(app.app.exec_())
